package com.xsqd.util;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.google.common.collect.Lists;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@UtilityClass
public class SqlExchanger {

    @SneakyThrows
    public String parseInsert(List<?> entitiesToInsert) {
        String insert = "insert into " + getTableName(entitiesToInsert.get(0).getClass());
        if (entitiesToInsert.isEmpty()) return "";
        Class<?> entityClass = entitiesToInsert.get(0).getClass();
        List<String> tableColumns = getColumns(entityClass);
        List<List<Object>> rows = Lists.newArrayList();
        for (Object entity : entitiesToInsert) {
            List<Object> values = getObjectValues(entity);
            rows.add(values);
        }
        StringBuilder sb = new StringBuilder(insert).append(getTableName(entityClass));
        appendColumns(tableColumns, sb);
        appendRows(rows, sb);
        return sb.toString();
    }

    @SneakyThrows
    public <T> List<String> parseUpdate(List<T> entitiesToUpdate) {
        // update ? set () values () where id = 1;
        // update ? set () values () where id = 2;
        Class<?> entityClass = entitiesToUpdate.get(0).getClass();
        StringBuilder sb = new StringBuilder("update " + getTableName(entityClass) + " set ");
        appendColumns(getColumns(entityClass), sb);
        String update = sb.toString(); // update ? set () values
        return entitiesToUpdate.stream().map(x -> getUpdate(update, x)).collect(Collectors.toList());
    }


    public <T> String parseDelete(List<T> entitiesToInsert) {
        return "";
    }

    @SneakyThrows
    public String getUpdate(String update, Object entity) {
        List<Object> objectValues = getObjectValues(entity);
        StringBuilder sb = new StringBuilder(update).append(" ( ");
        objectValues.forEach(x -> {
            if(x instanceof String){
                x = "'"+x+"'";
            }
            sb.append(x).append(",");
        });
        sb.deleteCharAt(sb.length() - 1);
        sb.append(") where row_hash = ");
        Field rowHash = entity.getClass().getDeclaredField("rowHash");
        rowHash.setAccessible(true);
        sb.append(rowHash.get(entity)).append(";");
        rowHash.setAccessible(false);
        return sb.toString();
    }


    public void appendColumns(List<String> tableColumns, StringBuilder sb) {
        sb.append(" (");
        // insert into table (a, b, c) values
        tableColumns.forEach(x -> {
            sb.append(x).append(",");
        });
        sb.deleteCharAt(sb.length() - 1);
        sb.append(") values ");
    }


    public void appendRows(List<List<Object>> rows, StringBuilder sb) {
        rows.forEach(x -> {
            sb.append(" ( ");
            x.forEach(y -> {
                if(y instanceof String){
                    y = "'"+y+"'";
                }
                sb.append(y).append(",");
            });
            sb.deleteCharAt(sb.length() - 1);
            sb.append(" ),");
        });
        // insert into table () values (),(),() ;
        sb.deleteCharAt(sb.length() - 1);
        sb.append(";");
    }

    public String getTableName(Class<?> entityClass) {
        TableName tableName = entityClass.getAnnotation(TableName.class);
        if (Objects.isNull(tableName)) {
            throw new RuntimeException("请给表名 谢谢");
        }
        return tableName.value();
    }

    public List<Object> getObjectValues(Object entity) {
        List<Object> values = Lists.newArrayList();
        Class<?> entityClass = entity.getClass();
        ReflectionUtils.doWithFields(entityClass, (f) -> {
            f.setAccessible(true);
            values.add(f.get(entity));
            f.setAccessible(false);
        });
        return values;
    }

    public List<String> getColumns(Class<?> entityClass) {
        List<String> columns = Lists.newArrayList();
        ReflectionUtils.doWithFields(entityClass, (field) -> {
            field.setAccessible(true);
            TableId tableId = field.getAnnotation(TableId.class);
            TableField tableField = field.getAnnotation(TableField.class);
            if (Objects.nonNull(tableId) && Objects.nonNull(tableField)) {
                throw new RuntimeException("@TableId @TableField 同时存在");
            }
            if (Objects.nonNull(tableId)) {
                columns.add(tableId.value());
            }
            if (Objects.nonNull(tableField)) {
                columns.add(tableField.value());
            }
            field.setAccessible(false);
        });
        return columns;
    }



}

